package com.zxl.register.server.core;

import com.zxl.register.base.Result;
import com.zxl.register.base.ServiceInstance;
import com.zxl.register.server.config.RegisterServerConfig;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


/**
 * 服务注册核心 .  因为采用和redis相同的单线程处理模式，所以整个数据结构设计采用效率最高的模型.
 *
 * created by  : zxl
 * on : 2019-12-18
 *
 */
public class ServiceRegistCore {

    /**
     * 总服务列表 {name,{provider,list<address>}}
     *
     */
    private static Map<String,Map<Boolean,List<String>>> serviceList=new HashMap();


    /**
     * 所有连接到服务注册中心的instance. {address,instance}
     */
    private static Map<String,ServiceInstance> allInstance=new HashMap<>();

    private static final String PROVIDER="provider";

    private static final String CONSUMER="consumer";



    /**
     * 根据 名称与消费者标识 查询服务信息
     * @return
     */
    public static Result findServiceInfoByName(String name){
       Map<Boolean,List<String>> serviceInfo =serviceList.get(name);
       if(CollectionUtils.isEmpty(serviceInfo)){
        return Result.processSuccess("没有对应的服务信息",null);
       }

        // 返回用的服务信息
       Map<String,List<ServiceInstance>> data=new HashMap();

        // 提供者信息
       List<ServiceInstance> providerInfo= serviceInfo.get(true)
               .stream()
               .map(e->{
                   return allInstance.get(e);
               }).collect(Collectors.toList());


       if( !CollectionUtils.isEmpty(providerInfo) ){
            data.put(PROVIDER,providerInfo);
       }

        // 消费者信息
       List<ServiceInstance> consumerInfo= serviceInfo.get(false)
               .stream()
               .map(e->{
                   return allInstance.get(e);
               }).collect(Collectors.toList());

        if( !CollectionUtils.isEmpty(consumerInfo) ){
            data.put(CONSUMER,providerInfo);
        }

        return Result.processSuccess("查询完成",data);

    }


    /**
     * 注册服务
     * @param instance
     * @return
     */
    public static Result register(ServiceInstance instance){
        instance.setLastHeartBeat(instance.getRegisterdTime());
        allInstance.put(instance.getAddress(),instance);
        if(addProvider(instance).isSuccess()&& addConsumer(instance).isSuccess()){
            return Result.processSuccess(null,null);
        }
        return Result.processFail("发生错误",null);
    }

    /**
     * 注册服务提供者
     * @param instance
     * @return
     */
    private static Result addProvider(ServiceInstance instance){
        if(!StringUtils.isEmpty(instance.getProvideServiceName())){
            for (String serviceName:instance.getProvideServiceName().split(",")) {
                registerNewInstance(instance.getAddress(),true,serviceName);
            }
        }
        return Result.processSuccess(null,null);
    }

    /**
     * 注册服务消费者
     * @param instance
     * @return
     */
    private static Result addConsumer(ServiceInstance instance){
        if(!StringUtils.isEmpty(instance.getSubscribeServiceName())){
            for (String serviceName:instance.getSubscribeServiceName().split(",")) {
                registerNewInstance(instance.getAddress(),false,serviceName);
            }
        }
        return Result.processSuccess(null,null);
    }

    /**
     * serviceList 中添加address
     * @param address
     * @return
     */
    private static Result registerNewInstance(String address ,boolean providerFlag,String serviceName){
        List<String> instanceList=null;

        // 根据name查instance的map
        Map<Boolean,List<String>> existAddressMap=serviceList.get(serviceName);

        if( CollectionUtils.isEmpty(existAddressMap) ){
            existAddressMap=new HashMap<>();
        }

        // 根据提供者与消费者标识 查 instanceList
        instanceList=existAddressMap.get(providerFlag);

        if(CollectionUtils.isEmpty(instanceList)){
            instanceList=new ArrayList();
        }

        instanceList.add(address);
        existAddressMap.put(providerFlag,instanceList);
        serviceList.put(serviceName,existAddressMap);

        return Result.processSuccess(null,null);
    }


    /**
     * 根据name和flag获取一个服务
     * @param name
     * @param providerFlag
     * @return
     */
    public static Result getOneService(String name,boolean providerFlag){
        Map<Boolean,List<String>>  serviceMap=serviceList.get(name);
        if(serviceMap!=null){
            List<String>  instanceList=serviceMap.get(providerFlag ? PROVIDER:CONSUMER);
            if(!CollectionUtils.isEmpty(instanceList)){
                return Result.processSuccess("处理成功",getInstanceByStrategy(instanceList));
            }
            return Result.processFail("不存在该服务",null);
        }
        return Result.processFail("不存在该服务",null);
    }

    /**
     * 获取一个可用的服务提供者信息
     * @param name 服务名称
     * @return
     */
    public static Result getOneServiceProvider(String name){
        return getOneService(name,true);
    }


    /**
     * 获取一个可用的服务消费者
     * @param name
     * @return
     */
    public static Result getOneServiceConsumer(String name) {
        return getOneService(name,false);
    }

    /** todo: 根据不同策略返回instance
     *
     * @param instanceList
     * @return
     */
    private static ServiceInstance getInstanceByStrategy(List<String> instanceList) {
        return allInstance.get(instanceList.get(0));
    }


    /**
     * 处理心跳
     * @param address
     * @return
     */
    public static void processHeartBeat(String address) {
        // 已经存在的instance
        ServiceInstance  existInstance =allInstance.get(address);
        existInstance.setLastHeartBeat(System.currentTimeMillis());
    }


    public static boolean updateInstanceByCheckHeartBeat() {
        try {
            allInstance.values().stream()
                    .filter(e-> e.getLastHeartBeat()+RegisterServerConfig.getInstance().getTimeOut() > System.currentTimeMillis())
                    .map(e->{
                        e.setStatus(2);
                        return null;})
                    .close();
            return true;
        }catch (Exception e){
            e.printStackTrace();
            return false;
        }
    }

    public static Result subscribe(String address, String serviceNames) {
        processHeartBeat(address);
        for (String name:serviceNames.split(",")) {
            registerNewInstance(address,false,serviceNames);
        }
        return Result.processFail("不存在该服务",null);
    }
}
